package br.com;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import br.com.entidade.Acorde;
import br.com.entidade.Intervalo;
import br.com.entidade.Nota;

public class Factory {

	private Factory() {
		super();
	}
	
	public static Factory getInstance()
	{
		return new Factory();
	}

	public Acorde createAcorde(Nota tonica, Acorde.Tipo tipo) {
		List<Nota> notas = new ArrayList<Nota>();
		Intervalo[] intervalos = tipo.getIntervalos();
		for (int i = 0; i < intervalos.length; i++) {
			notas.add(getNota(tonica, intervalos[i]));
		}
		return new Acorde(notas, tonica.getCifragem() + tipo.getCifragem());
	}

	private List<Nota> criarCromatica(Nota tonica) {
		List<Nota> cromaticaPadrao = Arrays.asList(Nota.values());
		List<Nota> cromatica = new ArrayList<Nota>(12);
		int indexTonica = cromaticaPadrao.indexOf(tonica);
		cromatica.addAll(cromaticaPadrao.subList(indexTonica, cromaticaPadrao
				.size()));
		cromatica.addAll(cromaticaPadrao.subList(0, indexTonica));
		return cromatica;
	}

	public Nota getNota(Nota tonica, Intervalo intervalo) {
		List<Nota> cromatica = criarCromatica(tonica);
		return cromatica.get(intervalo.getQtd());
	}

	public List<Acorde> createCampoHarmonicoMaior(Nota tonica) {
		List<Acorde> acordes = new ArrayList<Acorde>(11);
		List<Nota> cromatica = criarCromatica(tonica);
		acordes.add(createAcorde(cromatica.get(0), Acorde.Tipo.MAIOR));
		acordes.add(createAcorde(cromatica.get(2), Acorde.Tipo.MENOR));
		acordes.add(createAcorde(cromatica.get(4), Acorde.Tipo.MENOR));
		acordes.add(createAcorde(cromatica.get(5), Acorde.Tipo.MAIOR));
		acordes.add(createAcorde(cromatica.get(7), Acorde.Tipo.MAIOR));
		acordes.add(createAcorde(cromatica.get(5), Acorde.Tipo.MENOR));
		acordes.add(createAcorde(cromatica.get(6), Acorde.Tipo.MEIO_DIMINUTO));
		return acordes;
	}

	public List<Nota> getNotasEmComum(Acorde a, Acorde b) {
		List<Nota> notasA = a.getNotas();
		List<Nota> notasB = b.getNotas();
		List<Nota> intersecao = new ArrayList<Nota>(5);
		for (Nota notaA : notasA) {
			if (notasB.contains(notaA)) {
				intersecao.add(notaA);
			}
		}
		return intersecao;
	}

	public List<Acorde> getAcordesAfins(Acorde acorde, int afinidade) {
		Nota[] notas = Nota.values();
		Set<Acorde> acordesAfins = new HashSet<Acorde>();
		for (int i = 0; i < notas.length; i++) {
			List<Acorde> acordes = createCampoHarmonicoMaior(notas[i]);
			for (Acorde a : acordes) {
				if (verificarAfinidade(a, acorde, afinidade)) {
					acordesAfins.add(a);
				}
			}
		}
		return new ArrayList<Acorde>(acordesAfins);
	}

	private boolean verificarAfinidade(Acorde a, Acorde b, int afinidade) {
		List<Nota> notasEmComum = getNotasEmComum(a, b);
		return notasEmComum.size() >= afinidade;
	}

	/*
	 * public List<Nota> criarDiatonica(Nota tonica) { List<Nota> cromatica =
	 * criarCromatica(tonica); List<Nota> notas = new ArrayList<Nota>(7);
	 * notas.add(cromatica.get(0)); notas.add(cromatica.get(2));
	 * notas.add(cromatica.get(4)); notas.add(cromatica.get(5));
	 * notas.add(cromatica.get(7)); notas.add(cromatica.get(9));
	 * notas.add(cromatica.get(11)); return notas; }
	 */

}